public {{#is_final}}final {{/is_final}}{{#in_class}}static {{/in_class}}class {{name}} extends TUnion<{{name}}, {{name}}._Fields> {
  {{#i_2}}{{>generate_struct_desc}}{{/i_2}}
  {{#i_2}}{{>generate_field_descs}}{{/i_2}}
  {{#i_2}}{{>generate_field_name_constants}}{{/i_2}}
  {{#i_2}}{{>generate_java_meta_data_map}}{{/i_2}}

  public {{name}}() {
    super();
  }

  public {{name}}(_Fields setField, Object value) {
    super(setField, value);
  }

  public {{name}}({{{struct_type_name}}} other) {
    super(other);
  }

  public {{name}} deepCopy() {
    return new {{name}}(this);
  }

  {{#fields}}
  public static {{{struct_type_name}}} {{name}}({{{field_type.type_name}}} value) {
    {{{struct_type_name}}} x = new {{{struct_type_name}}}();
    x.set{{#cap}}{{name}}{{/cap}}(value);
    return x;
  }
  {{/fields}}

  @java.lang.Override
  protected void checkType(_Fields setField, Object value) throws ClassCastException {
    switch (setField) {
      {{#fields}}
      case {{#constant_name}}{{name}}{{/constant_name}}:
        if (value instanceof {{{field_type.type_name_in_container_skip_generic}}}) {
          break;
        }
        throw new ClassCastException("Was expecting value of type {{{field_type.type_name_in_container}}} for field '{{name}}', but got " + value.getClass().getSimpleName());
      {{/fields}}
      default:
        throw new IllegalArgumentException("Unknown field id " + setField);
    }
  }

  @java.lang.Override
  protected Object readValue(TProtocol iprot, TField field) throws TException {
    _Fields setField = _Fields.findByThriftId(field.id);
    if (setField != null) {
      switch (setField) {
        {{#fields}}
        case {{#constant_name}}{{name}}{{/constant_name}}:
          if (field.type == {{#constant_name}}{{name}}{{/constant_name}}_FIELD_DESC.type) {
            {{{field_type.type_name_in_container}}} {{name}};
            {{{deserialize_field}}}
            return {{name}};
          } else {
            TProtocolUtil.skip(iprot, field.type);
            return null;
          }
        {{/fields}}
        default:
          throw new IllegalStateException("setField wasn't null, but didn't match any of the case statements!");
      }
    } else {
      TProtocolUtil.skip(iprot, field.type);
      return null;
    }
  }

  @java.lang.Override
  protected void writeValue(TProtocol oprot) throws TException {
    switch (setField_) {
      {{#fields}}
      case {{#constant_name}}{{name}}{{/constant_name}}:
        {{{field_type.type_name_in_container}}} {{name}} = ({{{field_type.type_name_in_container}}})value_;
        {{{serialize_field}}}
        return;
      {{/fields}}
      default:
        throw new IllegalStateException("Cannot write union with unknown field " + setField_);
    }
  }

  @java.lang.Override
  protected TField getFieldDesc(_Fields setField) {
    switch (setField) {
      {{#fields}}
      case {{#constant_name}}{{name}}{{/constant_name}}:
        return {{#constant_name}}{{name}}{{/constant_name}}_FIELD_DESC;
      {{/fields}}
      default:
        throw new IllegalArgumentException("Unknown field id " + setField);
    }
  }

  @java.lang.Override
  protected TStruct getStructDesc() {
    return STRUCT_DESC;
  }

  @java.lang.Override
  protected _Fields enumForId(short id) {
    return _Fields.findByThriftIdOrThrow(id);
  }

  {{#i_2}}{{>generate_java_struct_field_by_id}}{{/i_2}}

  {{#fields}}
  public {{{field_type.type_name}}} get{{#cap}}{{name}}{{/cap}}() {
    if (getSetField() == _Fields.{{#constant_name}}{{name}}{{/constant_name}}) {
      return ({{{field_type.type_name_in_container}}})getFieldValue();
    } else {
      throw new RuntimeException("Cannot get field '{{name}}' because union is currently set to " + getFieldDesc(getSetField()).name);
    }
  }

  public void set{{#cap}}{{name}}{{/cap}}({{{field_type.type_name}}} value) {
    {{#field_type.nullable}}
    if (value == null) throw new NullPointerException();
    {{/field_type.nullable}}
    setField_ = _Fields.{{#constant_name}}{{name}}{{/constant_name}};
    value_ = value;
  }
  {{/fields}}

  public boolean equals(Object other) {
    if (other instanceof {{name}}) {
      return equals(({{name}})other);
    } else {
      return false;
    }
  }

  public boolean equals({{name}} other) {
    return other != null && getSetField() == other.getSetField() && getFieldValue().equals(other.getFieldValue());
  }

  @java.lang.Override
  public int compareTo({{{struct_type_name}}} other) {
    int lastComparison = TBaseHelper.compareTo(getSetField(), other.getSetField());
    if (lastComparison == 0) {
      return TBaseHelper.compareTo(getFieldValue(), other.getFieldValue());
    }
    return lastComparison;
  }

  {{^gen_hash_code}}
  /**
   * If you'd like this to perform more respectably, use the hashcode generator option.
   */
  {{/gen_hash_code}}
  @java.lang.Override
  public int hashCode() {
    {{#gen_hash_code}}
    HashCodeBuilder hcb = new HashCodeBuilder();
    hcb.append(this.getClass().getName());
    TFieldIdEnum setField = getSetField();
    if (setField != null) {
      hcb.append(setField.getThriftFieldId());
      Object value = getFieldValue();
      if (value instanceof TEnum) {
        hcb.append(((TEnum)getFieldValue()).getValue());
      } else {
        hcb.append(value);
      }
    }
    return hcb.toHashCode();
    {{/gen_hash_code}}
    {{^gen_hash_code}}
    return 0;
    {{/gen_hash_code}}
  }
}
